<?php
/*********************************************
 *  CPG Dragonfly™ CMS
 *********************************************
	Copyright © since 2010 by CPG-Nuke Dev Team
	http://dragonflycms.org

	Dragonfly is released under the terms and conditions
	of the GNU GPL version 2 or any later version
*/

namespace Poodle;

abstract class Crypt_Base
{
	protected $options = array(
		'cipher'      => 'twofish',
		'mode'        => 'cbc',
		'salt'        => 'Poodle WCMS',
		'compression' => null,
	);

	protected static $compressors = array(
		'gz' => array(
			'encode' => array('fname' => 'gzcompress', 'args' => array(null, 9), 'data_arg' => 0),
			'decode' => array('fname' => 'gzuncompress'),
			'desc'   => 'RFC 1950 ZLib compression'
		),
		'gz_deflate' => array(
			'encode' => array('fname' => 'gzdeflate',  'args' => array(null, 9), 'data_arg' => 0),
			'decode' => array('fname' => 'gzinflate'),
			'desc'   => 'RFC 1951 ZLib deflate'
		),
		'bz' => array(
			'encode' => array('fname' => 'bzcompress', 'args' => array(null, 9, 30), 'data_arg' => 0),
			'decode' => array('fname' => 'bzdecompress'),
			'desc'   => 'BZip2 compress, using work factor 30'
		),
	);

	function __construct(array $options=array())
	{
		foreach ($this->options as $k => $v)
		{
			if (!empty($options[$k])) { $v = $options[$k]; }
		}
		foreach (self::$compressors as $k => $v)
		{
			if (!function_exists($v['encode']['fname']) || !function_exists($v['decode']['fname'])) { unset(self::$compressors[$k]); }
		}
	}

	public static function listCompressors()
	{
		$list = array(''=>'none');
		foreach (self::$compressors as $k => $v) { $list[$k] = $v['desc']; }
		return $list;
	}

	protected function compressor(&$data, $decode=false)
	{
		if (!$this->options['compression']) { return true; }
		if (!isset(self::$compressors[$this->options['compression']])) { return false; }
		$compressor = self::$compressors[$this->options['compression']][$decode?'decode':'encode'];
		if (isset($compressor['args'])) {
			if (!isset($compressor['data_arg'])) { return false; }
			$largs = $compressor['args'];
			$largs[$compressor['data_arg']] = $data;
			$data = call_user_func_array($compressor['fname'], $largs);
		} else {
			$data = $compressor['fname']($data);
		}
		return true;
	}

	protected function Scramble(&$data, &$weakkey)
	{
		$strongkey = sha1($this->options['salt'] . $weakkey);
		$keysize   = strlen($strongkey);
		$datasize  = strlen($data);
		$output    = str_repeat(' ', $datasize);
		$di = $ki  = -1;
		while (++$di < $datasize) {
			if (++$ki >= $keysize) { $ki = 0; }
			$output[$di] = chr((ord($data[$di]) + ord($strongkey[$ki])) % 256);
		}
		return $output;
	}

	protected function Descramble(&$data, &$weakkey)
	{
		$strongkey = sha1($this->options['salt'] . $weakkey);
		$output    = str_repeat(' ', strlen($data));
		$keysize   = strlen($strongkey);
		$datasize  = strlen($data);
		$di = $ki  = -1;
		while (++$di < $datasize) {
			if (++$ki >= $keysize) { $ki = 0; }
			$work = (ord($data[$di]) - ord($strongkey[$ki]));
			if ($work < 0) { $work += 256; }
			$output[$di] = chr($work);
		}
		return $output;
	}

	# Virtual methods
	public static function listCiphers() {}
	public static function listModes()   {}
	public function Encrypt(&$Data, $WeakKey)       {}
	public function Decrypt(&$SecretData, $WeakKey) {}
}

if (function_exists('mcrypt_module_open')) {
	require(__DIR__.'/mcrypt.php');
	class Crypt extends \Poodle\Crypt\Mcrypt {}
//	class_alias('Poodle\\Crypt\\Mcrypt', 'Poodle\\Crypt');
} else {
	trigger_error('mcrypt not installed');
	require(__DIR__.'/fallback.php');
	class Crypt extends \Poodle\Crypt\Fallback {}
//	class_alias('Poodle\\Crypt\\Fallback', 'Poodle\\Crypt');
}
